//Modulo de leitura e escrita de memÃ³ria

module MEM(clk, icode, valE, valA, valP, enable, mem_data_i, mem_addr, mem_data_o, mem_write_e, data_o, WAIT, mem_ub, mem_lb);
input clk;

input [3:0] icode;
input [31:0] valE;
input [31:0] valP;
input [31:0] valA;

input enable;

input [15:0] mem_data_i;
output reg [31:0] mem_addr;
output reg [15:0] mem_data_o;
output mem_write_e;
output reg [31:0] data_o;
output reg WAIT;
output reg mem_ub;
output reg mem_lb;

reg [31:0] addr;
reg write_e = 0;
reg [31:0] data_i;
reg mem_enable = 0;

reg [1:0] counter;
reg is_align;

assign mem_write_e = write_e;

//////////////////BLOCO DE LÃ“GICA DE INSTRUÃ‡Ã•ES///////////////////

always @(*) begin
	if(enable) begin
		case(icode) 
			0, 1, 2, 3, 6, 7: begin
				mem_enable = 0;
				write_e = 0;
			end
			
			4: begin
				mem_enable = 1;
				write_e = 1;
				addr = valE;
				data_i = valA;
			end	
			5: begin
				mem_enable = 1;
				write_e = 0;
				addr = valE;
			end
			8, 10: begin
				mem_enable = 1;
				write_e = 1;
				addr = valE;
				data_i = valP;
			end
			9, 11: begin
				mem_enable = 1;
				write_e = 0;
				addr = valA;
			end
		endcase
	
	end else begin
		write_e = 0;
		mem_enable = 0;
	end

end

//////////////////BLOCO DE ACESSO A MEMÃ“RIA///////////////////


always @(negedge clk) begin
	if (mem_enable) begin
		if(!write_e) begin
			if(is_align) begin
				if(counter == 0) begin
					data_o[15:0] = mem_data_i;
					WAIT = 1;
				end else if(counter == 1) begin
					data_o[31:16] = mem_data_i;
					WAIT = 0;
				end
			end else begin
				if(counter == 0) begin
					data_o[7:0] = mem_data_i[15:8];
					WAIT = 1;
				end else if(counter == 1) begin
					data_o[23:8] = mem_data_i;
					WAIT = 1;
				end else if(counter == 2) begin
					data_o[31:24] = mem_data_i[7:0];
					WAIT = 0;
				end
			end
		end else begin
			if(is_align) begin
				if(counter == 0) begin
					mem_data_o = data_i[15:0];
					WAIT = 1;
				end else if(counter == 1) begin
					mem_data_o = data_i[31:16];
					WAIT = 0;
				end
			end else begin
				if(counter == 0) begin
					mem_data_o[15:8] = data_i[7:0];
					WAIT = 1;
				end else if(counter == 1) begin
					mem_data_o = data_i[23:8];
					WAIT = 1;
				end else if(counter == 2) begin
					mem_data_o[7:0] = data_i[31:24];
					WAIT = 0;
				end
			end
		end
	end else begin
		WAIT = 0;
	end
end

always @(posedge clk or posedge mem_enable) begin
	if(mem_enable) begin
		if(!WAIT) begin
			//se pc for impar ele comeÃ§a a ler do segundo byte da celula de memÃ³ria
			//acesso desalinhado
			mem_addr = (addr >> 1);
			is_align = !addr[0];
			counter = 2'b0;
		end else begin
			mem_addr = mem_addr + 1;
			counter = counter + 2'b1;
		end
		
		//LOGICA DE UB E LB
		if(!write_e) begin
			mem_ub = 1;
			mem_lb = 1;
		end else begin
			if(is_align) begin
				mem_ub = 1;
				mem_lb = 1;
			end else begin
				if(counter == 0) begin
					mem_ub = 1;
					mem_lb = 0;
				end else if(counter == 1) begin
					mem_ub = 1;
					mem_lb = 1;
				end else if(counter == 2) begin
					mem_ub = 0;
					mem_lb = 1;
				end
			end
		end
	end
	else begin
		counter = 0;
		mem_ub = 0;
		mem_lb = 0;
	end
	
end

endmodule
